import { AnimationClip, Asset, Component, instantiate, isValid, Node, Prefab, sp, Sprite, SpriteFrame, Texture2D, VideoPlayer } from "cc";
import { app } from "../../App";
import { injectable } from "../../inject";
import { Logger } from "../log/Logger";

@injectable('UILoader')
export default class UILoader {

    private loadResList = new Set<Asset>();

    refHandle(asset: Asset, target: Node) {
        if (asset.refCount === 0) {
            asset.addRef();
            this.loadResList.add(asset);
        }

        asset.addRef();

        let comp: Component = target.addComponent(Component);
        comp['onDestroy'] = () => {
            if (asset.refCount === 1) {
                return;
            }
            asset.decRef();
            // Logger.debug('asset.decRef: ', asset.name);
            // Logger.debug('asset.refCount: ', asset.refCount);
        }
    }

    freeLoadedRes() {
        this.loadResList.forEach((asset) => {
            asset.decRef();

            if (asset.refCount > 0) {
                Logger.warn('freeLoadedRes asset.refCount > 0', asset.name);
            }
        });

        this.loadResList.clear();
    }

    async renderSpine(path: string, target: sp.Skeleton): Promise<sp.SkeletonData> {
        const skeletonData = await app.res.loadASync(path, sp.SkeletonData);
        if (!isValid(target, true)) {
            Logger.warn('renderSpine: Spine渲染目标已销毁');
            return;
        }

        if (!isValid(skeletonData, true)) {
            return null
        }

        target.skeletonData = skeletonData;
        this.refHandle(skeletonData, target.node);

        return skeletonData;
    }

    async renderSprite(path: string, target: Sprite): Promise<SpriteFrame> {
        const frame = await app.res.loadASync(path, SpriteFrame);
        if (!isValid(target, true)) {
            Logger.warn('renderSprite: Sprite渲染目标已销毁');
            return;
        }

        if (!isValid(frame, true)) {
            return null;
        }

        target.spriteFrame = frame;
        this.refHandle(frame, target.node);

        return frame;
    }

    async renderPrefab(path: string, parentNode: Node, siblingIndex?: number): Promise<Node> {
        const prefab = await app.res.loadASync(path, Prefab);

        if (!isValid(prefab, true)) {
            return null;
        }

        const node = instantiate(prefab);

        if (!isValid(parentNode, true)) {
            Logger.warn('renderPrefab: parentNode已销毁');
            return;
        }

        if (siblingIndex != undefined) {
            parentNode.insertChild(node, siblingIndex);
        } else {
            parentNode.addChild(node);
        }
        this.refHandle(prefab, node);
        return node;
    }

    async renderVideo(path: string, videoPlayer: VideoPlayer) {
        if (!path) {
            return Promise.reject("renderVideo path参数错误");
        }

        let clip = await app.res.loadASync(path, Asset);
        if (!isValid(videoPlayer, true)) {
            Logger.error('videoPlayer已销毁');
            return;
        }
        videoPlayer.clip = clip;

        return clip;
    }

    async renderAnimation(path: string, animation: Animation, animName?: string) {
        const animClip = await app.res.loadASync(path, AnimationClip);

        // if (!isValid(animation, true)) {
        //     Logger.warn('animation-node已销毁');
        //     return;
        // }

        // if (animName) {
        //     animation.addClip(animClip, animName);
        //     animation.
        //     animation.play();
        // }
        // else {
        //     animation.addClip(animClip);
        // }

        // this.refHandle(animClip, animation.node);

        return animClip;
    }

    async renderRemoteSprite(remoteUrl: string, target: Sprite) {

        return new Promise((resolve, reject) => {
            app.res.loadRemote<Texture2D>(remoteUrl, (err: Error, texture: Texture2D) => {
                if (err) {
                    Logger.warn('[资源加载] 错误:', err, remoteUrl);
                    reject();
                    return;
                }
                if (!isValid(target, true)) {
                    Logger.warn('renderRemoteSprite: Sprite渲染目标已销毁');
                    reject();
                    return;
                }
                const spriteFrame = new SpriteFrame();
                spriteFrame.texture = texture;
                target.spriteFrame = spriteFrame;
                this.refHandle(spriteFrame, target.node);
                resolve(spriteFrame);
            });

        });


    }

    async loadRemoteTextAssets(remoteUrl: string) {
        return new Promise((resolve, reject) => {
            app.res.loadRemote(remoteUrl, (err, textAsset) => {
                if (err) {
                    Logger.warn('[资源加载] 错误:', err, remoteUrl);
                    reject();
                    return;
                }
                resolve(textAsset);
            });
        });
    }
}